﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Drawing.Drawing2D;
using ArtMath.Core.Data;
using ArtMath.Data;
using ArtMath.Setting;
using ArtMath.Core.Helper;
using ArtMath.Attribute;
using ArtMath.Converter;
using ArtMath.CommonType;
using ArtMath.Helper;

namespace ArtMath.Component.Annotation
{
    [Serializable]
    public abstract class CustomBase : Base
    {
        RPointS location;
        [Browsable(false)]
        public PointD Pxy { get; protected set; }
        SizeS size;
        bool showBorder = Settings.Instance.ShowBorder, fitSize = Settings.Instance.FitSize, transforming;
        PadStringX borderWidth;
        protected double selfRotateAngle;
        protected ColorX borderColor;
        DashStyle borderStyle = Settings.Instance.BorderDashStyle;

        public CustomBase(SketchPad pad, string name, ToolTypeName toolType, bool addToList = true) : base(pad, name, toolType, addToList)
        {
            if (Pad.CoordinateType == CoordinateSystemType.PolarCoordinate)
            {
                Location = new PPointS(Pad);
            }
            else
            {
                Location = new RPointS(Pad);
            }
            Size = new SizeS(Pad);
            BorderThickness = new PadStringX(Pad, Settings.Instance.BorderWidth);
            borderColor = new ColorX(Pad, Settings.Instance.BorderColor);
        }
        public override PointD MassPoint
        {
            get
            {
                return Pad.PxyToXY(DrawRegion.Center.RotateAt(DrawRegion.Location, -selfRotateAngle));
            }
        }
        public override PointD AnchorPoint(PropertyDisplayer disp)
        {
            return Pxy;
        }
        public virtual void SizeChanged(SizeD oldValue, SizeD newValue)
        {

        }

        public virtual void LocationChanged(PointD oldValue, PointD newValue)
        {
            Pxy = Pad.XYToPxy(newValue);
        }
        public override void Move(PointD offset, bool isCompulsive = false, Base sender = null)
        {
            Location.SetFromPointD(Pad.PxyToMath(Pxy + offset));
        }
        public override void RotateAngleChanged(double oldValue)
        {
            base.RotateAngleChanged(oldValue);
            double angleDelta = RotateAngle.RadValue - Pad.GetRad(oldValue);
            PointD center = RotateCenter.ToPointD();
            if (Settings.Instance.SelfRotate)
            {
                selfRotateAngle = RotateAngle.RadValue;
            }
            else
            {
                center -= MassPoint - Location.ToPointD();
            }
            PointD tmp = Location.ToPointD().RotateAt(center, angleDelta);
            Location.SetFromPointD(Pad.ShowPoint(tmp));
        }
        [Browsable(false)]
        public bool Transforming
        {
            get { return transforming; }
            set
            {
                transforming = true;
            }
        }
        [Browsable(false)]
        public virtual SizeF ActualSize
        {
            get
            {
                return Size.ToSizeF();
            }
        }

        [MultilingualCategory("Layout"), MultilingualDisplayName("Location")]
        public RPointS Location
        {
            get { return location; }
            set
            {
                if (location != null)
                {
                    location.CoordinateChanged -= LocationChanged;
                }
                location = value;
                if (location != null)
                {
                    location.CoordinateChanged += LocationChanged;
                }
            }
        }
        [MultilingualCategory("Layout"), MultilingualDisplayName("FitSize"), DefaultValue(typeof(bool), "True"), TypeConverter(typeof(ArtMath.Converter.BooleanConverter))]
        public virtual bool FitSize
        {
            get { return fitSize; }
            set
            {
                fitSize = value;
                Pad.Canvas.Invalidate();
            }
        }
        [MultilingualCategory("Layout"), MultilingualDisplayName("Size")]
        public virtual SizeS Size
        {
            get { return size; }
            set
            {
                if (size != null)
                {
                    size.SizeChanged -= SizeChanged;
                }
                size = value;
                if (size != null)
                {
                    size.SizeChanged += SizeChanged;
                }
            }
        }
        [MultilingualCategory("View"), MultilingualDisplayName(null, "Show", "Border"), DefaultValue(typeof(bool), "True"), TypeConverter(typeof(ArtMath.Converter.BooleanConverter))]
        public virtual bool ShowBorder
        {
            get { return showBorder; }
            set
            {
                showBorder = value;
                Pad.Canvas.Invalidate();
            }
        }
        [MultilingualCategory("Appearance"), MultilingualDisplayName(null, "Border", "Thickness"), DefaultValue(typeof(PadStringX), "1")]
        public PadStringX BorderThickness
        {
            get { return borderWidth; }
            set { borderWidth = value; }
        }
        [MultilingualCategory("Appearance"), MultilingualDisplayName("BorderDashStyle"), DefaultValue(typeof(DashStyle), "Solid"), TypeConverter(typeof(DashStyleConverter))]
        public DashStyle BorderDashStyle
        {
            get { return borderStyle; }
            set
            {
                borderStyle = value;
                if (ShowBorder)
                {
                    Pad.Canvas.Invalidate();
                }
            }
        }
        [MultilingualCategory("Appearance"), MultilingualDisplayName(null, "Border", "Color"), DefaultValue(typeof(Color), "Black")]
        public Color BorderColor
        {
            get { return borderColor.Color; }
            set { borderColor.Color = value; }
        }
        [Browsable(false)]
        public RectangleD DrawRegion
        {
            get { return new RectangleD(Pxy, SizeD.FromSizeF(ActualSize)).ToStandardRectangle(); }
        }
        public override bool Selected
        {
            get
            {
                return base.Selected;
            }

            set
            {
                base.Selected = value;
                if (LayerItem != null)
                {
                    LayerItem.Selected = Selected;
                }
            }
        }
        public override void CreateComponents()
        {
            if (Pad.TrackObj == this) Pad.TrackObj = null;
            if (Pad.HostObj == this) Pad.HostObj = null;
            base.CreateComponents();
        }
        public override Base[] CheckNearBy(PointD Plocation)
        {
            if (DrawRegion.Contains(Plocation))
            {
                return new Base[] { this };
            }
            return base.CheckNearBy(Plocation);
        }
        public override void CheckInRegion(RectangleD rect)
        {
            SetInPicker(rect.IntersectRectangle(DrawRegion));
        }
        public override void Paint(Graphics gra)
        {
            if (ObjectState == ObjectState.Normal && Visible && ShowBorder)
            {
                RectangleD rect = DrawRegion;
                gra.Transform(rect.Location, Settings.Instance.SelfRotate ? -RotateAngle.DegreeValue : -selfRotateAngle * Core.Helper.Angle.RToD, () =>
                {
                    Pen P = new Pen(BorderColor, BorderThickness.FloatValue)
                    {
                        DashStyle = BorderDashStyle
                    };
                    gra.DrawRectangle(P, 0, 0, (float)rect.Width, (float)rect.Height);
                });
            }
            base.Paint(gra);
        }
        /// <summary>
        /// 为自由变换时绘制变换后的影像
        /// </summary>
        /// <param name="gra"></param>
        public virtual void PaintLight(Graphics gra)
        {
            RectangleD rect = DrawRegion;
            Pen P = new Pen(BorderColor.HSVOffset(0, Settings.Instance.TransformSaturationOffset, 0), BorderThickness.FloatValue)
            {
                DashStyle = BorderDashStyle
            };
            gra.DrawRectangle(P, 0, 0, (float)rect.Width, (float)rect.Height);
        }
        public override bool LocationUsed(IList<PointD> locations)
        {
            return Location.ToPointD().AlmostEquals(locations[0], false);
        }
        public override void CoordinateSystemTypeChanged()
        {
            base.CoordinateSystemTypeChanged();
            PointD tmp = Pad.ConvertRPointS(Location, Pad.OldCoordinate);
            if (Pad.CoordinateType == CoordinateSystemType.PolarCoordinate)
            {
                Location = new PPointS(Pad, tmp.X.ToString(), tmp.Y.ToString());
            }
            else
            {
                Location = new RPointS(Pad, tmp.X.ToString(), tmp.Y.ToString());
            }
            //Location.SetFromPointD(tmp.Value);
            Pxy = Pad.XYToPxy(Location.ToPointD());
        }
    }
}
